package com.berchen.阻塞与非阻塞;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * 使用NIO完成网络通信的三个通信：
 *  1、通道（Channel）：负责连接。
 *      java.nio.channels.Channel接口：
 *          |--SelectableChannel    // 网络通道
 *              |--SocketChannel
 *              |--ServerSocketChannel
 *              |--DatagramChannel
 *
 *              管道
 *              |--Pipe.SinkChannel
 *              |--Pipe.SourceChannel
 *
 *  2、缓冲区（Buffer）：负责数据的存取。
 *  3、选择器（Selector）：是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况。
 */
public class TestBlock {

    // 现在还是阻塞式的

    // 客户端
    @Test
    public void client() throws IOException {

        // 1. 获取通道
        SocketChannel sChannel = SocketChannel.open(
                new InetSocketAddress("127.0.0.1", 10001)); // 网络通道
        FileChannel inChannel=FileChannel.open(     // 本地通道
                Paths.get("D:\\JavaProject\\Project\\All_Project\\Others_Project\\JavaNIO\\src\\1.jpg"),
                StandardOpenOption.READ);

        // 2.分配指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        // 3.读取本地文件并发送到服务端去
        while (inChannel.read(buf)!=-1){    // 从本地通道中读取数据放到缓冲区中
            buf.flip(); // 将缓冲区更改为读模式
            sChannel.write(buf);    // 将缓冲区的数据写到网络通道中
            buf.clear();
        }
        // 4.关闭通道
        inChannel.close();
        sChannel.close();
    }
    // 服务端
    @Test
    public void server() throws IOException {

        // 1. 获取通道
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
        FileChannel fileChannel = FileChannel.open(
                Paths.get("D:\\JavaProject\\Project\\All_Project\\Others_Project\\JavaNIO\\src\\wangluo.jpg"),
                StandardOpenOption.WRITE,
                StandardOpenOption.READ,
                StandardOpenOption.CREATE);

        // 2. 绑定端口号
        ssChannel.bind(new InetSocketAddress(10001));
        
        // 3.获取客户端连接的通道
        SocketChannel sChannel = ssChannel.accept();
        
        // 4. 分配指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);

        // 5.读取客户端发送的数据
        while (sChannel.read(buf)!=-1){
            buf.flip();
            fileChannel.write(buf);
            buf.clear();
        }

        // 6.关闭通道
        sChannel.close();
        fileChannel.close();
        ssChannel.close();
    }
}
